mod parser;

use pest::error::{InputLocation, LineColLocation};
use pest::Parser;
pub use parser::*;

fn main() -> anyhow::Result<()> {
    let args = std::env::args().collect::<Vec<_>>();
    let content = std::fs::read_to_string(&args[1])?;

    if let Ok(mut pairs) = SysYParser::parse(Rule::program, &content) {
        let all_pairs: Vec<_> = pairs.next().unwrap().into_inner().collect();

        let mut has_error = false;
        let mut errors = Vec::new();
        for pair in all_pairs.iter() {
            if pair.as_rule() == Rule::unknown_token {
                has_error = true;
                let (line, _) = pair.as_span().start_pos().line_col();
                let error_char = pair.as_str();
                errors.push(format!("Error type A at Line {line}: Mysterious character \"{error_char}\"."));
            }
        }

        if has_error {
            for error_msg in errors {
                eprintln!("{}", error_msg);
            }
            return Ok(());
        }
        for pair in all_pairs {
            let (line, _) = pair.as_span().start_pos().line_col();
            match pair.as_rule() {
                Rule::EOI => {}
                _ => {
                    let rule_name = format!("{:?}", pair.as_rule());
                    let content_str = match pair.as_rule() {
                        Rule::INTEGER_CONST => {
                            let str = pair.as_str();
                            if str.starts_with("0x") || str.starts_with("0X") {
                                i32::from_str_radix(&str[2..], 16)?.to_string()
                            } else if str.starts_with('0') && str.len() > 1 {
                                i32::from_str_radix(&str[1..], 8).or_else(|_| i32::from_str_radix(str, 8)).unwrap().to_string()
                            } else {
                                i32::from_str_radix(str, 10)?.to_string()
                            }
                        }
                        _ => pair.as_str().to_string(),
                    };
                    eprintln!("{rule_name} {content_str} at Line {line}.")
                }
            }
        }
    }
    Ok(())
}
